home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / octa209s.zip / octave-2.09 / src / input.cc < prev    next >
C/C++ Source or Header  |  1997-05-28  |  27KB  |  1,387 lines

  1. /*
  2.  
  3. Copyright (C) 1996 John W. Eaton
  4.  
  5. This file is part of Octave.
  6.  
  7. Octave is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU General Public License as published by the
  9. Free Software Foundation; either version 2, or (at your option) any
  10. later version.
  11.  
  12. Octave is distributed in the hope that it will be useful, but WITHOUT
  13. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with Octave; see the file COPYING.  If not, write to the Free
  19. Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20.  
  21. */
  22.  
  23. /*
  24.  
  25. The 2 functions listed below were adapted from similar functions
  26. from GNU Bash, the Bourne Again SHell, copyright (C) 1987, 1989, 1991
  27. Free Software Foundation, Inc.
  28.  
  29.   read_octal    decode_prompt_string
  30.  
  31. */
  32.  
  33. /* Modified by Klaus Gebhardt, 1996 */
  34.  
  35. // Use the GNU readline library for command line editing and hisory.
  36.  
  37. #ifdef HAVE_CONFIG_H
  38. #include <config.h>
  39. #endif
  40.  
  41. #include <ctime>
  42. #include <cstdio>
  43. #include <cstdlib>
  44. #include <cstring>
  45. #include <cassert>
  46. #include <csignal>
  47.  
  48. #include <string>
  49.  
  50. #include <iostream.h>
  51.  
  52. #ifdef HAVE_UNISTD_H
  53. #ifdef HAVE_SYS_TYPES_H
  54. #include <sys/types.h>
  55. #endif
  56. #include <unistd.h>
  57. #endif
  58.  
  59. #if defined (USE_READLINE)
  60. #include <readline/readline.h>
  61. #include <readline/history.h>
  62. #endif
  63.  
  64. #include "str-vec.h"
  65.  
  66. #include "defun.h"
  67. #include "dirfns.h"
  68. #include "error.h"
  69. #include "gripes.h"
  70. #include "help.h"
  71. #include "input.h"
  72. #include "oct-map.h"
  73. #include "oct-hist.h"
  74. #include "toplev.h"
  75. #include "oct-obj.h"
  76. #include "pager.h"
  77. #include "parse.h"
  78. #include "pathlen.h"
  79. #include "pt-const.h"
  80. #include "sighandlers.h"
  81. #include "symtab.h"
  82. #include "sysdep.h"
  83. #include "utils.h"
  84. #include "variables.h"
  85.  
  86. // Primary prompt string.
  87. static string Vps1;
  88.  
  89. // Secondary prompt string.
  90. static string Vps2;
  91.  
  92. // String printed before echoed input (enabled by --echo-input).
  93. string Vps4;
  94.  
  95. // Character to append after successful command-line completion attempts.
  96. static char Vcompletion_append_char;
  97.  
  98. // Global pointer for eval().
  99. string current_eval_string;
  100.  
  101. // Nonzero means get input from current_eval_string.
  102. int get_input_from_eval_string = 0;
  103.  
  104. // Nonzero means we're parsing a function file.
  105. int reading_fcn_file = 0;
  106.  
  107. // Simple name of function file we are reading.
  108. string curr_fcn_file_name;
  109.  
  110. // Full name of file we are reading.
  111. string curr_fcn_file_full_name;
  112.  
  113. // Nonzero means we're parsing a script file.
  114. int reading_script_file = 0;
  115.  
  116. // If we are reading from an M-file, this is it.
  117. FILE *ff_instream = 0;
  118.  
  119. // Nonzero means this is an interactive shell.
  120. int interactive = 0;
  121.  
  122. // Nonzero means the user forced this shell to be interactive (-i).
  123. int forced_interactive = 0;
  124.  
  125. // Nonzero means the user forced this shell to be really interactive (-i),
  126. // but without using the pager.
  127. int really_forced_interactive = 0;
  128.  
  129. // Should we issue a prompt?
  130. int promptflag = 1;
  131.  
  132. // The current line of input, from wherever.
  133. string current_input_line;
  134.  
  135. // TRUE after a call to completion_matches().
  136. bool octave_completion_matches_called = false;
  137.  
  138. // Return the octal number parsed from STRING, or -1 to indicate that
  139. // the string contained a bad number.
  140.  
  141. static int
  142. read_octal (const string& s)
  143. {
  144.   int result = 0;
  145.   int digits = 0;
  146.  
  147.   size_t i = 0;
  148.   size_t slen = s.length ();
  149.  
  150.   while (i < slen && s[i] >= '0' && s[i] < '8')
  151.     {
  152.       digits++;
  153.       result = (result * 8) + s[i] - '0';
  154.       i++;
  155.     }
  156.  
  157.   if (! digits || result > 0777 || i < slen)
  158.     result = -1;
  159.  
  160.   return result;
  161. }
  162.  
  163. // Return a string which will be printed as a prompt.  The string may
  164. // contain special characters which are decoded as follows: 
  165. //   
  166. //    \t    the time
  167. //    \d    the date
  168. //    \n    CRLF
  169. //    \s    the name of the shell (program)
  170. //    \w    the current working directory
  171. //    \W    the last element of PWD
  172. //    \u    your username
  173. //    \h    the hostname
  174. //    \#    the command number of this command
  175. //    \!    the history number of this command
  176. //    \$    a $ or a # if you are root
  177. //    \<octal> character code in octal
  178. //    \\    a backslash
  179.  
  180. static string
  181. decode_prompt_string (const string& s)
  182. {
  183.   string result;
  184.   string temp;
  185.   size_t i = 0;
  186.   size_t slen = s.length ();
  187.   int c;
  188.  
  189.   while (i < slen)
  190.     {
  191.       c = s[i];
  192.  
  193.       i++;
  194.  
  195.       if (c == '\\')
  196.     {
  197.       c = s[i];
  198.  
  199.       switch (c)
  200.         {
  201.         case '0':
  202.         case '1':
  203.         case '2':
  204.         case '3':
  205.         case '4':
  206.         case '5':
  207.         case '6':
  208.         case '7':
  209.           // Maybe convert an octal number.
  210.           {
  211.         int n = read_octal (s.substr (i, 3));
  212.  
  213.         temp = "\\";
  214.  
  215.         if (n != -1)
  216.           {
  217.             i += 3;
  218.             temp[0] = n;
  219.           }
  220.  
  221.         c = 0;
  222.         goto add_string;
  223.           }
  224.       
  225.         case 't':
  226.         case 'd':
  227.           // Make the current time/date into a string.
  228.           {
  229.         time_t now = time (0);
  230.  
  231.         temp = ctime (&now);
  232.  
  233.         if (c == 't')
  234.           {
  235.             temp = temp.substr (11);
  236.             temp.resize (8);
  237.           }
  238.         else
  239.           temp.resize (10);
  240.  
  241.         goto add_string;
  242.           }
  243.  
  244.         case 'n':
  245.           {
  246.         if (using_readline)
  247.           temp = "\r\n";
  248.         else
  249.           temp = "\n";
  250.  
  251.         goto add_string;
  252.           }
  253.  
  254.         case 's':
  255.           {
  256.         temp = base_pathname (Vprogram_name);
  257.  
  258.         goto add_string;
  259.           }
  260.     
  261.         case 'w':
  262.         case 'W':
  263.           {
  264. #define EFFICIENT
  265. #ifdef EFFICIENT
  266.         // Use the value of PWD because it is much more
  267.         // effecient.
  268.  
  269.         temp = Vcurrent_directory;
  270.  
  271.         if (temp.empty ())
  272.           temp = octave_getcwd ();
  273. #else
  274.         temp = octave_getcwd ();
  275. #endif    /* EFFICIENT */
  276.  
  277.         if (c == 'W')
  278.           {
  279.             size_t pos = temp.rfind ('/');
  280.  
  281.             if (pos != NPOS && pos != 0)
  282.               temp = temp.substr (pos + 1);
  283.           }
  284.         else
  285.           temp = polite_directory_format (temp);
  286.  
  287.         goto add_string;
  288.           }
  289.       
  290.         case 'u':
  291.           {
  292.         temp = Vuser_name;
  293.  
  294.         goto add_string;
  295.           }
  296.  
  297.         case 'H':
  298.           {
  299.         temp = Vhost_name;
  300.  
  301.         goto add_string;
  302.           }
  303.  
  304.         case 'h':
  305.           {
  306.         temp = Vhost_name;
  307.  
  308.         size_t pos = temp.find ('.');
  309.  
  310.         if (pos != NPOS)
  311.           temp.resize (pos);
  312.         
  313.         goto add_string;
  314.           }
  315.  
  316.         case '#':
  317.           {
  318.         char number_buffer[128];
  319.         sprintf (number_buffer, "%d", current_command_number);
  320.         temp = number_buffer;
  321.  
  322.         goto add_string;
  323.           }
  324.  
  325.         case '!':
  326.           {
  327.         char number_buffer[128];
  328.         int num = octave_command_history.current_number ();
  329.         if (num > 0)
  330.                   sprintf (number_buffer, "%d", num);
  331.         else
  332.           strcpy (number_buffer, "!");
  333.         temp = number_buffer;
  334.  
  335.         goto add_string;
  336.           }
  337.  
  338.         case '$':
  339.           {
  340.         temp = (geteuid () == 0 ? "#" : "$");
  341.  
  342.         goto add_string;
  343.           }
  344.  
  345.         case '[':
  346.         case ']':
  347.           {
  348.         temp.resize (2);
  349.  
  350.         temp[0] = '\001';
  351.         temp[1] = ((c == '[')
  352.                ? RL_PROMPT_START_IGNORE
  353.                : RL_PROMPT_END_IGNORE);
  354.  
  355.         goto add_string;
  356.           }
  357.  
  358.         case '\\':
  359.           {
  360.         temp = "\\";
  361.  
  362.         goto add_string;
  363.           }
  364.  
  365.         default:
  366.           {
  367.         temp = "\\ ";
  368.         temp[1] = c;
  369.  
  370.         goto add_string;
  371.           }
  372.  
  373.         add_string:
  374.           {
  375.         if (c)
  376.           i++;
  377.  
  378.         result.append (temp);
  379.  
  380.         break;
  381.           }
  382.         }
  383.     }
  384.       else
  385.     result += c;
  386.     }
  387.  
  388.   return result;
  389. }
  390.  
  391. static void
  392. do_input_echo (const string& input_string)
  393. {
  394.   int do_echo = reading_script_file ?
  395.     (Vecho_executing_commands & ECHO_SCRIPTS)
  396.       : (Vecho_executing_commands & ECHO_CMD_LINE) && ! forced_interactive;
  397.  
  398.   if (do_echo)
  399.     {
  400.       if (forced_interactive)
  401.     {
  402.       if (promptflag > 0)
  403.         octave_stdout << decode_prompt_string (Vps1);
  404.       else
  405.         octave_stdout << decode_prompt_string (Vps2);
  406.     }
  407.       else
  408.     octave_stdout << decode_prompt_string (Vps4);
  409.  
  410.       if (! input_string.empty ())
  411.     {
  412.       octave_stdout << input_string;
  413.  
  414.       if (input_string[input_string.length () - 1] != '\n')
  415.         octave_stdout << "\n";
  416.     }
  417.     }
  418. }
  419.  
  420. char *
  421. gnu_readline (const char *s, bool force_readline)
  422. {
  423.   char *retval = 0;
  424.  
  425.   if (using_readline || force_readline)
  426.     {
  427.       char *tmp = retval = ::readline (s);
  428.  
  429.       if (tmp && strlen (tmp) == 0)
  430.     {
  431.       retval = (char *) malloc (2);
  432.       retval[0] = '\n';
  433.       retval[1] = '\0';
  434.     }
  435.     }
  436.   else
  437.     {
  438.       if (s && *s &&
  439.       (interactive || forced_interactive || really_forced_interactive))
  440.     {
  441.       fprintf (rl_outstream, s);
  442.       fflush (rl_outstream);
  443.     }
  444.  
  445.       FILE *curr_stream = rl_instream;
  446.       if (reading_fcn_file || reading_script_file)
  447.     curr_stream = ff_instream;
  448.  
  449.       int grow_size = 1024;
  450.       int max_size = grow_size;
  451.  
  452.       char *buf = (char *) malloc (max_size);
  453.       char *bufptr = buf;
  454.       int len = 0;
  455.  
  456.       do
  457.     {
  458.       if (fgets (bufptr, grow_size, curr_stream))
  459.         {
  460.           len = strlen (bufptr);
  461.  
  462.           if (len == grow_size - 1)
  463.         {
  464.           int tmp = bufptr - buf + grow_size - 1;
  465.           grow_size *= 2;
  466.           max_size += grow_size;
  467.           buf = (char *) realloc (buf, max_size);
  468.           bufptr = buf + tmp;
  469.  
  470.           if (*(bufptr-1) == '\n')
  471.             {
  472.               *bufptr = '\0';
  473.               retval = buf;
  474.             }
  475.         }
  476.           else if (bufptr[len-1] != '\n')
  477.         {
  478.           bufptr[len++] = '\n';
  479.           bufptr[len] = '\0';
  480.           retval = buf;
  481.         }
  482.           else
  483.         retval = buf;
  484.         }
  485.       else
  486.         {
  487.           if (len == 0)
  488.         free (buf);
  489.  
  490.           break;
  491.         }
  492.     }
  493.       while (! retval);
  494.     }
  495.  
  496.   return retval;
  497. }
  498.  
  499. static char *
  500. octave_gets (void)
  501. {
  502.   char *retval = 0;
  503.  
  504.   if ((interactive || forced_interactive || really_forced_interactive)
  505.       && (! (reading_fcn_file || reading_script_file)))
  506.     {
  507.       const char *ps = (promptflag > 0) ? Vps1.c_str () :
  508.     Vps2.c_str ();
  509.  
  510.       string prompt = decode_prompt_string (ps);
  511.  
  512.       pipe_handler_error_count = 0;
  513.  
  514.       flush_octave_stdout ();
  515.  
  516.       octave_diary << prompt;
  517.  
  518.       retval = gnu_readline (prompt.c_str ());
  519.     }
  520.   else
  521.     retval = gnu_readline ("");
  522.  
  523.   if (retval)
  524.     current_input_line = retval;
  525.   else
  526.     current_input_line = "";
  527.  
  528.   if (! current_input_line.empty ())
  529.     {
  530.       if (! input_from_startup_file)
  531.     octave_command_history.add (current_input_line);
  532.  
  533.       octave_diary << current_input_line;
  534.  
  535.       do_input_echo (current_input_line);
  536.     }
  537.  
  538.   octave_diary << "\n";
  539.   
  540.   return retval;
  541. }
  542.  
  543. // Read a line from the input stream.
  544.  
  545. static char *
  546. get_user_input (void)
  547. {
  548.   char *retval = 0;
  549.  
  550.   if (get_input_from_eval_string)
  551.     {
  552.       size_t len = current_eval_string.length ();
  553.  
  554.       retval = (char *) malloc (len + 2);
  555.  
  556.       strcpy (retval, current_eval_string.c_str ());
  557.  
  558.       retval[len++] = '\n';
  559.       retval[len] = '\0';    // Paranoia.
  560.     }
  561.   else
  562.     retval = octave_gets ();
  563.  
  564.   if (retval)
  565.     current_input_line = retval;
  566.  
  567.   if (! get_input_from_eval_string)
  568.     input_line_number++;
  569.  
  570.   return retval;
  571. }
  572.  
  573. int
  574. octave_read (char *buf, unsigned max_size)
  575. {
  576.   static char *input_buf = 0;
  577.   static char *cur_pos = 0;
  578.   static int chars_left = 0;
  579.  
  580.   int status = 0;
  581.  
  582.   if (! input_buf)
  583.     {
  584.       cur_pos = input_buf = get_user_input ();
  585.  
  586.       chars_left = input_buf ? strlen (input_buf) : 0;
  587.     }
  588.  
  589.   if (chars_left > 0)
  590.     {
  591.       buf[0] = '\0';
  592.  
  593.       int len = max_size - 2;
  594.  
  595.       strncpy (buf, cur_pos, len);
  596.  
  597.       if (chars_left > len)
  598.     {
  599.       chars_left -= len;
  600.  
  601.       cur_pos += len;
  602.  
  603.       buf[len] = '\0';
  604.  
  605.       status = len;
  606.     }
  607.       else
  608.     {
  609.       free (input_buf);
  610.       input_buf = 0;
  611.  
  612.       len = chars_left;
  613.  
  614.       if (buf[len-1] != '\n')
  615.         buf[len++] = '\n';
  616.  
  617.       buf[len] = '\0';
  618.  
  619.       status = len;
  620.     }
  621.     }
  622.   else if (chars_left == 0)
  623.     {
  624.       if (input_buf)
  625.     {
  626.       free (input_buf);
  627.       input_buf = 0;
  628.     }
  629.  
  630.       status = 0;
  631.     }
  632.   else    
  633.     status = -1;
  634.  
  635.   return status;
  636. }
  637.  
  638. // Fix things up so that input can come from file `name', printing a
  639. // warning if the file doesn't exist.
  640.  
  641. FILE *
  642. get_input_from_file (const string& name, int warn)
  643. {
  644.   FILE *instream = 0;
  645.  
  646.   if (name.length () > 0)
  647.     instream = fopen (name.c_str (), "rb");
  648.  
  649.   if (! instream && warn)
  650.     warning ("%s: no such file or directory", name.c_str ());
  651.  
  652.   if (reading_fcn_file || reading_script_file)
  653.     ff_instream = instream;
  654.   else
  655.     rl_instream = instream;
  656.  
  657.   return instream;
  658. }
  659.  
  660. // Fix things up so that input can come from the standard input.  This
  661. // may need to become much more complicated, which is why it's in a
  662. // separate function.
  663.  
  664. FILE *
  665. get_input_from_stdin (void)
  666. {
  667.   rl_instream = stdin;
  668.   return rl_instream;
  669. }
  670.  
  671. static string_vector
  672. generate_struct_completions (const char *text, char *& prefix,
  673.                  char *& hint)
  674. {
  675.   string_vector names;
  676.  
  677.   assert (text);
  678.  
  679.   char *id = strsave (text);
  680.   char *ptr = strchr (id, '.');
  681.   *ptr = '\0';
  682.  
  683.   char *elts = ptr + 1;
  684.   ptr = strrchr (elts, '.');
  685.   if (ptr)
  686.     *ptr = '\0';
  687.   else
  688.     elts = 0;
  689.  
  690.   prefix = strsave (text);
  691.   ptr = strrchr (prefix, '.');
  692.   *ptr = '\0';
  693.  
  694.   delete [] hint;
  695.   hint = strsave (ptr + 1);
  696.  
  697.   symbol_record *sr = curr_sym_tab->lookup (id, 0, 0);
  698.   if (! sr)
  699.     sr = global_sym_tab->lookup (id, 0, 0);
  700.  
  701.   if (sr && sr->is_defined ())
  702.     {
  703.       tree_fvc *tmp_fvc = sr->def ();
  704.  
  705.       tree_constant *def = 0;
  706.       if (tmp_fvc->is_constant ())
  707.     def = (tree_constant *) tmp_fvc;
  708.  
  709.       if (def && def->is_map ())
  710.     {
  711.       if (elts && *elts)
  712.         {
  713.           octave_value ult = def->lookup_map_element (elts, 0, 1);
  714.  
  715.           if (ult.is_map ())
  716.         {
  717.           Octave_map m = ult.map_value ();
  718.           names = m.make_name_list ();
  719.         }
  720.         }
  721.       else
  722.         {
  723.           Octave_map m = def->map_value ();
  724.           names = m.make_name_list ();
  725.         }
  726.     }
  727.     }
  728.  
  729.   delete [] id;
  730.  
  731.   return names;
  732. }
  733.  
  734. // XXX FIXME XXX -- make this generate file names when appropriate.
  735.  
  736. static string_vector
  737. generate_possible_completions (const char *text, char *& prefix,
  738.                    char *& hint)
  739. {
  740.   string_vector names;
  741.  
  742.   prefix = 0;
  743.  
  744.   if (text && *text && *text != '.' && strrchr (text, '.'))
  745.     names = generate_struct_completions (text, prefix, hint);
  746.   else
  747.     names = make_name_list ();
  748.  
  749.   names.qsort ();
  750.  
  751.   // Remove duplicates.
  752.  
  753.   // XXX FIXME XXX -- maybe this should be defined for all Array objects.
  754.  
  755.   int k = 0;
  756.  
  757.   int len = names.length ();
  758.  
  759.   for (int i = 1; i < len; i++)
  760.     {
  761.       if (names[i] != names[k])
  762.     {
  763.       k++;
  764.  
  765.       if (k != i)
  766.         names[k] = names[i];
  767.     }
  768.     }
  769.  
  770.   names.resize (k+1);
  771.  
  772.   return names;
  773. }
  774.  
  775. static int
  776. looks_like_struct (const char *nm)
  777. {
  778.   int retval = 0;
  779.  
  780.   assert (nm);
  781.  
  782.   char *id = strsave (nm);
  783.   char *elts = 0;
  784.   char *ptr = strchr (id, '.');
  785.   if (ptr)
  786.     {
  787.       *ptr = '\0';
  788.       elts = ptr + 1;
  789.     }
  790.  
  791.   symbol_record *sr = curr_sym_tab->lookup (id, 0, 0);
  792.   if (! sr)
  793.     sr = global_sym_tab->lookup (id, 0, 0);
  794.  
  795.   if (sr && sr->is_defined ())
  796.     {
  797.       tree_fvc *tmp_fvc = sr->def ();
  798.  
  799.       tree_constant *def = 0;
  800.       if (tmp_fvc->is_constant ())
  801.     def = (tree_constant *) tmp_fvc;
  802.  
  803.       if (def && def->is_map ())
  804.     {
  805.       if (elts && *elts)
  806.         {
  807.           octave_value ult = def->lookup_map_element (elts, 0, 1);
  808.  
  809.           if (ult.is_map ())
  810.         retval = 1;
  811.         }
  812.       else
  813.         retval = 1;
  814.     }
  815.     }
  816.  
  817.   delete [] id;
  818.  
  819.   return retval;    
  820. }
  821.  
  822. // XXX FIXME XXX -- this has to return a pointer to char, but it
  823. // should be converted to use a generating function that returns a
  824. // string_vector.
  825.  
  826. static char *
  827. command_generator (const char *text, int state)
  828. {
  829.   static char *prefix = 0;
  830.   static char *hint = 0;
  831.  
  832.   static int prefix_len = 0;
  833.   static int hint_len = 0;
  834.  
  835.   static int list_index = 0;
  836.   static int list_length = 0;
  837.   static string_vector name_list;
  838.  
  839.   static int matches = 0;
  840.  
  841.   if (state == 0)
  842.     {
  843.       list_index = 0;
  844.  
  845.       delete [] prefix;
  846.       prefix = 0;
  847.  
  848.       delete [] hint;
  849.       hint = strsave (text);
  850.  
  851.       name_list = generate_possible_completions (text, prefix, hint);
  852.  
  853.       prefix_len = 0;
  854.       if (prefix)
  855.     prefix_len = strlen (prefix);
  856.     
  857.       assert (hint);
  858.       hint_len = strlen (hint);
  859.  
  860.       matches = 0;
  861.  
  862.       list_length = name_list.length ();
  863.  
  864.       for (int i = 0; i < list_length; i++)
  865.     if (name_list[i].compare (hint, 0, hint_len))
  866.       matches++;
  867.     }
  868.  
  869.   if (list_length > 0 && matches > 0)
  870.     {
  871.       const char *name;
  872.  
  873.       while (list_index < list_length)
  874.     {
  875.       name = name_list[list_index].c_str ();
  876.  
  877.       list_index++;
  878.  
  879.       if (strncmp (name, hint, hint_len) == 0)
  880.         {
  881.           int len = 2 + prefix_len + strlen (name);
  882.           char *buf = (char *) malloc (len);
  883.  
  884.           if (prefix)
  885.         {
  886.           strcpy (buf, prefix);
  887.           strcat (buf, ".");
  888.           strcat (buf, name);
  889.         }
  890.           else
  891.         strcpy (buf, name);
  892.  
  893.           if (matches == 1 && looks_like_struct (buf))
  894.         rl_completion_append_character = '.';
  895.           else
  896.         rl_completion_append_character = Vcompletion_append_char;
  897.  
  898.           return buf;
  899.         }
  900.     }
  901.     }
  902.  
  903.   return 0;
  904. }
  905.  
  906. static char **
  907. command_completer (char *text, int /* start */, int /* end */)
  908. {
  909.   char **matches = 0;
  910.   matches = completion_matches (text, command_generator);
  911.   return matches;
  912. }
  913.  
  914. // The next two functions implement the equivalent of the K*rn shell
  915. // C-o operate-and-get-next-history-line editing command.  Stolen from
  916. // the GNU Bourne Again SHell.
  917.  
  918. // ??
  919. static int saved_history_line_to_use = 0;
  920.  
  921. // ??
  922. static Function *old_rl_startup_hook = 0;
  923.  
  924. static void
  925. set_saved_history (void)
  926. {
  927.   HIST_ENTRY *h;
  928.  
  929.   if (saved_history_line_to_use)
  930.     {
  931.       if (history_set_pos (saved_history_line_to_use))
  932.     {
  933.       h = current_history ();
  934.       if (h)
  935.         {
  936.           rl_insert_text (h->line);
  937.  
  938.           // Get rid of any undo list created by the previous
  939.           // insert, so the line won't totally be erased when the
  940.           // edits are undone (they will be normally, because this
  941.           // is a history  line -- cf. readline.c: line 380 or
  942.           // so).
  943.  
  944.           if (rl_undo_list)
  945.         {
  946.           free_undo_list ();
  947.           rl_undo_list = 0;
  948.         }
  949.         }
  950.     }
  951.     }
  952.   saved_history_line_to_use = 0;
  953.   rl_startup_hook = old_rl_startup_hook;
  954. }
  955.  
  956. static void
  957. operate_and_get_next (int /* count */, int /* c */)
  958. {
  959.   int where;
  960.  
  961.   // Accept the current line.
  962.  
  963.   rl_newline ();
  964.  
  965.   // Find the current line, and find the next line to use.
  966.  
  967.   where = where_history ();
  968.  
  969.   if ((history_is_stifled () && (history_length >= max_input_history))
  970.       || (where >= history_length - 1))
  971.     saved_history_line_to_use = where;
  972.   else
  973.     saved_history_line_to_use = where + 1;
  974.  
  975.   old_rl_startup_hook = rl_startup_hook;
  976.   rl_startup_hook = (Function *) set_saved_history;
  977. }
  978.  
  979. void
  980. initialize_readline (void)
  981. {
  982.   // Set things up internally in case some function that uses readline
  983.   // (currently Fclc(), maybe others) is called before readline().
  984.  
  985.   rl_initialize ();
  986.  
  987.   // Allow conditional parsing of the ~/.inputrc file
  988.  
  989.   rl_readline_name = "Octave";
  990.  
  991.   // Tell the completer that we want to try first.
  992.  
  993.   rl_attempted_completion_function = (CPPFunction *) command_completer;
  994.  
  995.   // Bind operate-and-get-next.
  996.  
  997.   rl_add_defun ("operate-and-get-next",
  998.         (Function *) operate_and_get_next, CTRL ('O'));
  999.  
  1000.  
  1001.   // And the history search functions.
  1002.  
  1003.   rl_add_defun ("history-search-backward",
  1004.         (Function *) rl_history_search_backward, META ('p'));
  1005.  
  1006.   rl_add_defun ("history-search-forward",
  1007.         (Function *) rl_history_search_forward, META ('n'));
  1008.  
  1009.   // Don't treat single quotes as string delimiters when doing paren
  1010.   // matching.
  1011.  
  1012.   rl_paren_string_delimiters = "\"";
  1013. }
  1014.  
  1015. static int
  1016. match_sans_spaces (const char *standard, const char *test)
  1017. {
  1018.   char *tmp = strsave (test);
  1019.  
  1020.   char *tp = tmp;
  1021.   while (*tp == ' ' || *tp == '\t')
  1022.     tp++;
  1023.  
  1024.   char *ep = tmp + strlen (tmp) - 1;
  1025.   while (*ep == ' ' || *ep == '\t')
  1026.     ep--;
  1027.  
  1028.   *(ep+1) = '\0';
  1029.  
  1030.   int retval = strcmp (standard, tp) == 0;
  1031.  
  1032.   delete [] tmp;
  1033.  
  1034.   return retval;
  1035.  
  1036. }
  1037.  
  1038. // If the user simply hits return, this will produce an empty matrix.
  1039.  
  1040. static octave_value_list
  1041. get_user_input (const octave_value_list& args, bool debug = false)
  1042. {
  1043.   octave_value retval;
  1044.  
  1045.   int nargin = args.length ();
  1046.  
  1047.   int read_as_string = 0;
  1048.  
  1049.   if (nargin == 2)
  1050.     read_as_string++;
  1051.  
  1052.   string prompt ("debug> ");
  1053.  
  1054.   if (nargin > 0)
  1055.    {
  1056.      prompt = args(0).string_value ();
  1057.  
  1058.      if (error_state)
  1059.        {
  1060.      error ("input: unrecognized argument");
  1061.      return retval;
  1062.        }
  1063.     }
  1064.  
  1065.  again:
  1066.  
  1067.   flush_octave_stdout ();
  1068.  
  1069.   char *input_buf = gnu_readline (prompt.c_str (), true);
  1070.  
  1071.   if (input_buf)
  1072.     {
  1073.       if (! input_from_startup_file)
  1074.     octave_command_history.add (input_buf);
  1075.  
  1076.       int len = strlen (input_buf);
  1077.  
  1078.       if (len < 1)
  1079.     {
  1080.       if (debug)
  1081.         goto again;
  1082.       else
  1083.         {
  1084.           if (read_as_string)
  1085.         return "";
  1086.           else
  1087.         return Matrix ();
  1088.         }
  1089.     }
  1090.  
  1091.       if (match_sans_spaces ("exit", input_buf)
  1092.       || match_sans_spaces ("quit", input_buf)
  1093.       || match_sans_spaces ("return", input_buf))
  1094.     {
  1095.       return retval;
  1096.     }
  1097.       else if (read_as_string)
  1098.     {
  1099.       retval = input_buf;
  1100.     }
  1101.       else
  1102.     {
  1103.       int parse_status = 0;
  1104.  
  1105.       retval = eval_string (input_buf, 0, parse_status);
  1106.  
  1107.       if (retval.is_defined ())
  1108.         {
  1109.           if (debug)
  1110.         retval.print ();
  1111.         }
  1112.       else
  1113.         retval = Matrix ();
  1114.     }
  1115.     }
  1116.   else
  1117.     error ("input: reading user-input failed!");
  1118.  
  1119.   if (debug)
  1120.     goto again;
  1121.  
  1122.   return retval;
  1123. }
  1124.  
  1125. DEFUN (input, args, ,
  1126.   "input (PROMPT [, S])\n\
  1127. \n\
  1128. Prompt user for input.  If the second argument is present, return\n\
  1129. value as a string.")
  1130. {
  1131.   octave_value_list retval;
  1132.  
  1133.   int nargin = args.length ();
  1134.  
  1135.   if (nargin == 1 || nargin == 2)
  1136.     retval = get_user_input (args);
  1137.   else
  1138.     print_usage ("input");
  1139.  
  1140.   return retval;
  1141. }
  1142.  
  1143. DEFUN (keyboard, args, ,
  1144.   "keyboard (PROMPT)\n\
  1145. \n\
  1146. maybe help in debugging function files")
  1147. {
  1148.   octave_value_list retval;
  1149.  
  1150.   int nargin = args.length ();
  1151.  
  1152.   if (nargin == 0 || nargin == 1)
  1153.     retval = get_user_input (args, true);
  1154.   else
  1155.     print_usage ("keyboard");
  1156.  
  1157.   return retval;
  1158. }
  1159.  
  1160. DEFUN_TEXT(echo, args, ,
  1161.   "echo [options]\n\
  1162. \n\
  1163.   echo [on|off]         -- enable or disable echoing of commands as\n\
  1164.                            they are executed in script files\n\
  1165. \n\
  1166.   echo [on all|off all] -- enable or disable echoing of commands as they\n\
  1167.                            are executed in script files and functions\n\
  1168. \n\
  1169. Without any arguments, toggle the current echo state.")
  1170. {
  1171.   octave_value_list retval;
  1172.  
  1173.   int argc = args.length () + 1;
  1174.  
  1175.   string_vector argv = args.make_argv ("echo");
  1176.  
  1177.   if (error_state)
  1178.     return retval;
  1179.  
  1180.   switch (argc)
  1181.     {
  1182.     case 1:
  1183.       {
  1184.     if ((Vecho_executing_commands & ECHO_SCRIPTS)
  1185.         || (Vecho_executing_commands & ECHO_FUNCTIONS))
  1186.       bind_builtin_variable ("echo_executing_commands",
  1187.                  (double) ECHO_OFF);
  1188.     else
  1189.       bind_builtin_variable ("echo_executing_commands",
  1190.                  (double) ECHO_SCRIPTS);
  1191.       }
  1192.       break;
  1193.  
  1194.     case 2:
  1195.       {
  1196.     string arg = argv[1];
  1197.  
  1198.     if (arg == "on")
  1199.       bind_builtin_variable ("echo_executing_commands",
  1200.                  (double) ECHO_SCRIPTS);
  1201.     else if (arg == "off")
  1202.       bind_builtin_variable ("echo_executing_commands",
  1203.                  (double) ECHO_OFF);
  1204.     else
  1205.       print_usage ("echo");
  1206.       }
  1207.       break;
  1208.  
  1209.     case 3:
  1210.       {
  1211.     string arg = argv[1];
  1212.  
  1213.     if (arg == "on" && argv[2] == "all")
  1214.       bind_builtin_variable ("echo_executing_commands",
  1215.                  (double) (ECHO_SCRIPTS | ECHO_FUNCTIONS));
  1216.     else if (arg == "off" && argv[2] == "all")
  1217.       bind_builtin_variable ("echo_executing_commands",
  1218.                  (double) ECHO_OFF);
  1219.     else
  1220.       print_usage ("echo");
  1221.       }
  1222.       break;
  1223.  
  1224.     default:
  1225.       print_usage ("echo");
  1226.       break;
  1227.     }
  1228.  
  1229.   return retval;
  1230. }
  1231.  
  1232. DEFUN (completion_matches, args, nargout,
  1233.   "completion_matches (HINT): generate possible completions given HINT\n\
  1234. \n\
  1235. This function is provided for the benefit of programs like Emacs which\n\
  1236. might be controlling Octave and handling user input.  The current command\n\
  1237. number is not incremented when this function is called.  This is a feature,\n\
  1238. not a bug.")
  1239. {
  1240.   octave_value retval;
  1241.  
  1242.   int nargin = args.length ();
  1243.  
  1244.   if (nargin == 1)
  1245.     {
  1246.       string hint_string = args(0).string_value ();
  1247.  
  1248.       if (! error_state)
  1249.     {
  1250.       int n = 32;
  1251.  
  1252.       string_vector list (n);
  1253.  
  1254.       const char *hint = hint_string.c_str ();
  1255.  
  1256.       int k = 0;
  1257.  
  1258.       for (;;)
  1259.         {
  1260.           const char *cmd = command_generator (hint, k);
  1261.  
  1262.           if (cmd)
  1263.         {
  1264.           if (*cmd)
  1265.             {
  1266.               if (k == n)
  1267.             {
  1268.               n *= 2;
  1269.               list.resize (n);
  1270.             }
  1271.  
  1272.               list[k++] = cmd;
  1273.             }
  1274.         }
  1275.           else
  1276.         {
  1277.           list.resize (k);
  1278.           break;
  1279.         }
  1280.         }
  1281.  
  1282.       if (nargout > 0)
  1283.         {
  1284.           if (! list.empty ())
  1285.         retval = list;
  1286.           else
  1287.         retval = "";
  1288.         }
  1289.       else
  1290.         {
  1291.           // We don't use string_vector::list_in_columns here
  1292.           // because it will be easier for Emacs if the names
  1293.           // appear in a single column.
  1294.  
  1295.           int len = list.length ();
  1296.  
  1297.           for (int i = 0; i < len; i++)
  1298.         octave_stdout << list[i] << "\n";
  1299.         }
  1300.  
  1301.       octave_completion_matches_called = true;
  1302.     }
  1303.     }
  1304.   else
  1305.     print_usage ("completion_matches");
  1306.  
  1307.   return retval;
  1308. }
  1309.  
  1310. static int
  1311. ps1 (void)
  1312. {
  1313.   int status = 0;
  1314.  
  1315.   Vps1 = builtin_string_variable ("PS1");
  1316.  
  1317.   return status;
  1318. }
  1319.  
  1320. static int
  1321. ps2 (void)
  1322. {
  1323.   int status = 0;
  1324.  
  1325.   Vps2 = builtin_string_variable ("PS2");
  1326.  
  1327.   return status;
  1328. }
  1329.  
  1330. static int
  1331. ps4 (void)
  1332. {
  1333.   int status = 0;
  1334.  
  1335.   Vps4 = builtin_string_variable ("PS4");
  1336.  
  1337.   return status;
  1338. }
  1339.  
  1340. static int
  1341. completion_append_char (void)
  1342. {
  1343.   int status = 0;
  1344.  
  1345.   string s = builtin_string_variable ("completion_append_char");
  1346.  
  1347.   switch (s.length ())
  1348.     {
  1349.     case 1:
  1350.       Vcompletion_append_char = s[0];
  1351.       break;
  1352.  
  1353.     case 0:
  1354.       Vcompletion_append_char = '\0';
  1355.       break;
  1356.  
  1357.     default:
  1358.       warning ("completion_append_char must be a single character");
  1359.       status = -1;
  1360.       break;
  1361.     }
  1362.  
  1363.   return status;
  1364. }
  1365.  
  1366. void
  1367. symbols_of_input (void)
  1368. {
  1369.   DEFVAR (PS1, "\\s:\\#> ", 0, ps1,
  1370.     "primary prompt string");
  1371.  
  1372.   DEFVAR (PS2, "> ", 0, ps2,
  1373.     "secondary prompt string");
  1374.  
  1375.   DEFVAR (PS4, "+ ", 0, ps4,
  1376.     "string printed before echoed input (enabled by --echo-input)");
  1377.  
  1378.   DEFVAR (completion_append_char, " ", 0, completion_append_char,
  1379.     "the string to append after successful command-line completion attempts");
  1380. }
  1381.  
  1382. /*
  1383. ;;; Local Variables: ***
  1384. ;;; mode: C++ ***
  1385. ;;; End: ***
  1386. */
  1387.